package controllers

import (
	"code.google.com/p/go.net/websocket"
	"html/template"
	"jk/jklog"
	"net/http"
	"strings"
)

type PageChat struct {
	Application
}

func init() {
	App.RegisterController("chat/", PageChat{})
}

func (p *PageChat) Login(rw http.ResponseWriter, req *http.Request) {
	p.Document.Title = "jmdkina的个人聊天室"
}

var innerName = map[string]string{
	"jmdkina":  "zhujn1224",
	"jmdvirus": "zhujn1224",
	"kina":     "zhujn1224",
	"kina.zjn": "zhujn1224",
}

type LoginInfo struct {
	Name     string
	RealName string
	Host     string
	Conn     *websocket.Conn
}

type LoginStatus struct {
	Status    string
	LoginInfo LoginInfo
}

type userInfo struct {
	Self       LoginInfo
	Relation   []LoginInfo
	NewMessage string
}

type Users struct {
	LoginInUsers []userInfo
}

type MessageInfo struct {
	Status   string
	Message  string
	SendUser LoginInfo
	UsersOn  Users
}

var onlineUsers Users

func nameExist(name string) string {
	for k, v := range innerName {
		if k == name {
			return v
		}
	}
	return ""
}

func userHasLogin(name string) bool {
	for _, v := range onlineUsers.LoginInUsers {
		if v.Self.Name == name {
			return true
		}
	}
	return false
}

func (p *PageChat) Chat(rw http.ResponseWriter, req *http.Request) {
	p.Document.Title = "jmdkina的个人聊天室"
	if req.Method == "POST" {
		if name, ok := p.POST["name"]; ok {
			p.Document.Title = "热烈欢迎" + name + "加入jk聊天室"
			if userHasLogin(name) == true {
				errStatus := LoginStatus{
					Status: "这个账号已经登录了，确定一下是不是你的哦。说不定别比你先用了这个名字",
				}
				p.Body = errStatus
				return
			}
			if v := nameExist(strings.Split(name, "@")[0]); v != "" {
				if v != p.POST["password"] {
					var status = ""
					if p.POST["password"] == "" {
						status = "这个用户名已经被使用的，如果是你注册的，记得输入密码哦^-^"
					} else {
						status = "你的密码好像弄错了，不记了的话要联系管理员啊"
					}
					errStatus := LoginStatus{
						Status: status,
					}
					p.Body = errStatus
					return
				}
			}

			if name == "" {
				loginStatus := LoginStatus{Status: "body, 你没写名字吧"}
				p.Body = loginStatus
				return
			}

			loginInfo := LoginInfo{
				Name:     name,
				RealName: strings.Split(name, "@")[0],
				Host:     req.Host,
			}
			loginStatus := LoginStatus{LoginInfo: loginInfo}
			p.Body = loginStatus
		}
	}
}

func (p *PageChat) AddUsers(rw http.ResponseWriter, req *http.Request) {
	if req.Method == "GET" {
		if self, ok := p.GET["self"]; ok {
			me := onlineUsers.findLoginUser(self)
			if name, ok := p.GET["name"]; ok {
				if name == "all" {
					me.addOnlineUsers(onlineUsers)
				} else {
					newU := onlineUsers.findLoginUser(name)
					me.addNewUser(newU.Self)
				}
			}
		}
	}
}

func UserConnection(ws *websocket.Conn) {
	jklog.L().Infoln(("User connection start"))
	name := ws.Request().URL.Query().Get("name")

	if name == "" {
		jklog.L().Errorln("Can't get the name")
		//return
	}

	name = template.HTMLEscapeString(name)

	onlineUser := LoginInfo{
		Name:     name,
		RealName: strings.Split(name, "@")[0],
		Conn:     ws,
	}

	loginInUser := userInfo{
		Self: onlineUser,
	}
	onlineUsers.LoginInUsers = append(onlineUsers.LoginInUsers, loginInUser)

	/* when one person come
	 * will send to all the new users
	 */
	onlineUsers.UpdateOnlineUsers()

	jklog.L().Infoln(("Start to receiver data"))
	loginInUser.ReceiverData()
	onlineUsers.ClearLoginUser(onlineUser)
}

func (liu userInfo) ReceiverData() {
	for {
		var content string
		err := websocket.Message.Receive(liu.Self.Conn, &content)
		// If user closes or refreshes the browser, a err will occur
		if err != nil {
			return
		}
		jklog.L().Infoln("---------", content)
		/* when I get data, I will send to other */
		onlineUsers.updateNewMessage(liu, content)
	}
}

func (u *Users) ClearLoginUser(login LoginInfo) {
	login.Conn.Close()
	var newLoginInfo []userInfo
	for _, v := range u.LoginInUsers {
		if v.Self.Name != login.Name {
			newLoginInfo = append(newLoginInfo, v)
		}
	}
	u.LoginInUsers = newLoginInfo
	/* If one user away,
	 * need update users
	 */
	u.UpdateOnlineUsers()
}

func (u *Users) UpdateOnlineUsers() {
	MsgInfo := MessageInfo{
		Status:  "MSG_USERS",
		UsersOn: *u,
	}
	for _, v := range u.LoginInUsers {
		websocket.JSON.Send(v.Self.Conn, MsgInfo)
	}
}

func (u *Users) findLoginUser(name string) *userInfo {
	for i, v := range u.LoginInUsers {
		if v.Self.RealName == name {
			return &u.LoginInUsers[i]
		}
	}
	return nil
}

/* add all online users to self */
func (ui *userInfo) addOnlineUsers(u Users) {
	newUsers := []LoginInfo{}
	for _, v := range u.LoginInUsers {
		if ui.Self.RealName == v.Self.RealName {
			continue
		} else {
			newUsers = append(newUsers, v.Self)
		}
	}
	ui.Relation = newUsers
}

/* add a new user */
func (u *userInfo) addNewUser(user LoginInfo) {
	for _, v := range u.Relation {
		if v.Name == user.Name {
			return
		}
	}
	u.Relation = append(u.Relation, user)
}

func (on Users) updateNewMessage(u userInfo, content string) {
	MsgInfo := MessageInfo{
		Status:   "MSG_NEW",
		Message:  content,
		SendUser: u.Self,
	}
	me := on.findLoginUser(u.Self.RealName)

	for _, v := range me.Relation {

		if v.Name == u.Self.Name {
			continue
		} else {
			jklog.L().Infoln("start to send message: ", MsgInfo.Message)
			websocket.JSON.Send(v.Conn, MsgInfo)
		}
	}
}
